home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume10 / cfc < prev    next >
Encoding:
Text File  |  1987-06-30  |  24.4 KB  |  1,263 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i033: "Compile" sendmail.cf files into EASE language
  5. Message-ID: <525@uunet.UU.NET>
  6. Date: 2 Jul 87 03:29:30 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1252
  9. Approved: rs@uunet.uu.net
  10.  
  11. Submitted by: emoryu1!arnold (Arnold D. Robbins)
  12. Mod.Sources: Volume 10, Number 33
  13. Archive-Name: cfc
  14.  
  15.     This program takes plain sendmail.cf files and translates them into
  16. almost usable ease input.  It is a simple stdin -> stdout filter.
  17.  
  18.     It will complain if your sendmail.cf file has problems. In particular,
  19. many $? conditional macros don't have the ending $. Cfc will complain.
  20.  
  21.     Anyway, I hope this is useful to those of you contemplating switching
  22. over to ease.
  23.  
  24. Arnold Robbins
  25.  
  26. [ I spliced the Makefile into the archive... --r$ ]
  27. ------------- you should know what to do by now ------------------------
  28. #! /bin/sh
  29. # This is a shell archive, meaning:
  30. # 1. Remove everything above the #! /bin/sh line.
  31. # 2. Save the resulting text in a file.
  32. # 3. Execute the file with /bin/sh (not csh) to create the files:
  33. #    cfc.1
  34. #    cfc.c
  35. #    Makefile
  36. # This archive created: Wed Apr  8 10:24:14 1987
  37. export PATH; PATH=/bin:$PATH
  38.  
  39. echo shar: extracting "'Makefile'" '(roughly 107 characters)'
  40. if test -f 'Makefile'
  41. then
  42.     echo shar: will not over-write existing file "'Makefile'"
  43. else
  44. cat << \SHAR_EOF > 'Makefile'
  45. cfc:        cfc.c
  46.     $(CC) $(CFLAGS) cfc.c -o cfc
  47. install:    cfc cfc.1
  48.     @echo install according to local conventions
  49. SHAR_EOF
  50. fi # end of overwriting check
  51.  
  52. echo shar: extracting "'cfc.1'" '(3038 characters)'
  53. if test -f 'cfc.1'
  54. then
  55.     echo shar: will not over-write existing file "'cfc.1'"
  56. else
  57. cat << \SHAR_EOF > 'cfc.1'
  58. ...
  59. ... $Header: cfc.1,v 1.2 87/04/08 10:21:47 arnold Locked $
  60. ... 
  61. ... $Log:    cfc.1,v $
  62. ... Revision 1.2  87/04/08  10:21:47  arnold
  63. ... Small bug fixes, compatibility option added, also warnings for
  64. ... unrecognized flags and options. ADR.
  65. ... 
  66. ... Revision 1.1  87/02/16  15:25:32  arnold
  67. ... Initial revision
  68. ... 
  69. ...
  70. .TH CFC 8 local
  71. .SH NAME
  72. cfc \- Sendmail cf file compiler
  73. .SH SYNOPSIS
  74. .B cfc
  75. [
  76. .B \-c
  77. ] <
  78. .I sendmail.cf-file
  79. >
  80. .I ease-source-file
  81. .SH DESCRIPTION
  82. .I Cfc
  83. is a filter that reads a raw
  84. .IR sendmail (8)
  85. configuration file on its standard input, and produces almost useable
  86. .IR ease (1)
  87. source on its standard output.
  88. .P
  89. It is designed as a conversion tool, to translate an existing
  90. .B sendmail.cf
  91. file into
  92. .I ease
  93. with the idea that all future work will be done in
  94. .IR ease .
  95. .P
  96. .I Cfc
  97. passes all comments through to the output, and converts all predefined
  98. .I sendmail
  99. macros, options, option values, and mailer flags into the names used by
  100. .IR ease .
  101. .P
  102. Once it is through, the user need only spend some time in a good screen
  103. editor doing the following:
  104. .RS
  105. .P
  106. Changing the RULESET_n names into more descriptive names, and
  107. adding ruleset bindings.
  108. .P
  109. Applying quoting to necessary string literals, principally in the
  110. definitions of headers. The
  111. .I ease
  112. documentation on header formats should be consulted.
  113. .P
  114. Adding new field names.
  115. .I Cfc
  116. just uses very generic field names, everywhere, when names like ``user,''
  117. ``host,'' and ``relay'' might be more descriptive.
  118. .P
  119. Miscellanious formatting.
  120. .I Cfc
  121. introduces tabs on its own, as well as often passing through tabs
  122. from the
  123. .I sendmail
  124. input.
  125. It will also print a header for each different type of line, e.g. if the
  126. input had seven
  127. .B O
  128. (option) lines, there will be seven option blocks.
  129. These are usually succesive, and can therefore be merged.
  130. Finally, the block close on rulesets often comes after the comments that
  131. precede the next ruleset or mailer specification.
  132. .RE
  133. .P
  134. In short,
  135. .I cfc
  136. does over 90% of the tedious work of translating a
  137. .B sendmail.cf
  138. into
  139. .I ease
  140. format.
  141. The rest of the work can be done in a day or less.
  142. Suprisingly, the combination of
  143. .I cfc
  144. and
  145. .I ease
  146. can find bugs in a current
  147. .B sendmail.cf
  148. file!
  149. .P
  150. .I Cfc takes one option,
  151. .BR \-c ,
  152. which indicates it should run in 4.2BSD compatibility mode.
  153. In this case, options and mailer flags which are new in the 4.3BSD
  154. version of
  155. .I sendmail
  156. will not be recognized.
  157. .\" .SH FILES
  158. .SH SEE ALSO
  159. .I "Sendmail Installation and Operation Guide"
  160. by Eric Allman,
  161. .I "Ease: A Configuration Language for Sendmail"
  162. by James S. Schoner,
  163. .IR sendmail (8),
  164. .IR ease (1)
  165. .SH DIAGNOSTICS
  166. ``\c
  167. .IR Routine :
  168. malformed input line
  169. .IR line :
  170. fatal error''
  171. for input it doesn't understand.
  172. .I Routine is the name of the routine in
  173. .I cfc
  174. which choked, and
  175. .I line
  176. is the line number in the input.
  177. .SH BUGS
  178. Only recognizes continuation lines (lines that begin with a \s-1TAB\s+1)
  179. for header (H) and mailer (M) definitions.
  180. .SH AUTHOR
  181. .nf
  182. Arnold Robbins
  183. Emory University Computing Center
  184. arnold@emory.edu
  185. .fi
  186. SHAR_EOF
  187. fi # end of overwriting check
  188. echo shar: extracting "'cfc.c'" '(19944 characters)'
  189. if test -f 'cfc.c'
  190. then
  191.     echo shar: will not over-write existing file "'cfc.c'"
  192. else
  193. cat << \SHAR_EOF > 'cfc.c'
  194. #ifndef lint
  195. static char RCSid[] = "$Header: cfc.c,v 1.3 87/04/08 10:23:02 root Locked $";
  196. #endif
  197.  
  198. /*
  199.  * $Log:    cfc.c,v $
  200.  * Revision 1.3  87/04/08  10:23:02  root
  201.  * Small bug fixes, compatibility option added, also warnings for
  202.  * unrecognized flags and options. ADR.
  203.  * 
  204.  * Revision 1.2  87/02/18  15:26:39  root
  205.  * Fix to recognize multidigit ruleset numbers in $> (calls) in RHS. ADR.
  206.  * 
  207.  * Revision 1.1  87/02/16  15:25:00  arnold
  208.  * Initial revision
  209.  * 
  210.  * Revision 1.1  87/02/16  15:25:00  arnold
  211.  * Initial revision
  212.  * 
  213.  */
  214.  
  215. /*
  216.  * cfc.c
  217.  *
  218.  * Sendmail cf file compiler.
  219.  * Reads a raw sendmail.cf file and produces ease source.
  220.  *
  221.  * There are very few comments in this source. You will need both the
  222.  * "Sendmail Installation and Operation Guide" and the paper on Ease
  223.  * to really understand this.
  224.  *
  225.  * Arnold Robbins
  226.  * Emory University Computing Center
  227.  * 2/87
  228.  */
  229.  
  230. #include <stdio.h>
  231. #include <ctype.h>
  232.  
  233. char buffer[BUFSIZ];
  234. int line = 0;
  235. int inruleset = 0;
  236.  
  237. extern char *macro ();        /* convert sendmail to ease macro names */
  238. extern char *mflags ();        /* convert sendmail to ease mailer flag names */
  239. extern char *optionname ();    /* convert sendmail to ease option names */
  240. extern char *delivoption ();    /* delivery options */
  241. extern char *handle_option ();    /* handling options */
  242.  
  243. extern char *ngets ();        /* buffered gets () routine */
  244. extern void ungets ();        /* put a buffer back for getting */
  245.  
  246. #define endruleset()    if (inruleset) { inruleset = 0; printf ("\t}\n"); }
  247.  
  248. int compat = 0;            /* complain about new 4.3 options & flags */
  249.  
  250. main (argc, argv)
  251. int argc;
  252. char **argv;
  253. {
  254.     if (argc > 1)
  255.     {
  256.         if (strcmp (argv[1], "-c") == 0)
  257.             compat = 1;
  258.         else
  259.         {
  260.             fprintf (stderr, "usage: %s [ -c ]\n", argv[0]);
  261.             fprintf (stderr, "illegal argument '%s' ignored\n",
  262.                     argv[1]);
  263.         }
  264.     }
  265.  
  266.     printf ("/******************************************************/\n");
  267.     printf ("/* This ease file generated by cfc from a sendmail.cf */\n");
  268.     printf ("/* file. It must be edited by hand before being fed   */\n");
  269.     printf ("/* to ease!                                           */\n");
  270.     printf ("/******************************************************/\n");
  271.     printf ("\n#define eval(x)\"$&\"x    /* for RUTGERS $& */\n");
  272.     printf ("\n\nbind\n\t/* RULESET BINDINGS GO HERE (cfc) */\n\n");
  273.  
  274.     /*
  275.      * For perfection, everything but the comment and rule cases
  276.      * should do an endruleset (), but practically speaking, it is
  277.      * usually only the mailer new ruleset definitions that end a
  278.      * previous ruleset. Occasionally a macro, too.
  279.      */
  280.  
  281.     while (ngets (buffer) != NULL)
  282.     {
  283.         line++;
  284.         switch (buffer[0]) {
  285.         case '#':
  286.             comment ();
  287.             continue;    /* skip code to end ruleset */
  288.         case 'S':
  289.             endruleset ();
  290.             ruleset ();
  291.             continue;    /* skip code to end ruleset */
  292.         case 'R':
  293.             rule ();
  294.             continue;    /* skip code to end ruleset */
  295.         case 'D':
  296.             endruleset ();
  297.             def ();
  298.             break;
  299.         case 'C':
  300.             class ();
  301.             break;
  302.         case 'F':
  303.             fileclass ();
  304.             break;
  305.         case 'M':
  306.             endruleset ();
  307.             mailer ();
  308.             break;
  309.         case 'H':
  310.             header ();
  311.             break;
  312.         case 'O':
  313.             option ();
  314.             break;
  315.         case 'T':
  316.             trusted ();
  317.             break;
  318.         case 'P':
  319.             precedence ();
  320.             break;
  321.         default:
  322.             other ();
  323.             continue;    /* skip code to end ruleset */
  324.         }
  325.         endruleset ();
  326.     }
  327.     endruleset ();        /* just in case */
  328. }
  329.  
  330. /* comment --- produce a comment */
  331.  
  332. comment ()
  333. {
  334.     static char format[] = "/* %s */\n";
  335.     register int i = strlen (buffer) - 1;
  336.  
  337.     /* try to be semi-intelligent about comments */
  338.  
  339.     if (buffer[1] == '\0')
  340.         printf ("\n");
  341.     else if (isspace (buffer[1]) && buffer[i] != '#')
  342.     {
  343.         for (i = 1; isspace (buffer[i]); i++)
  344.             ;
  345.         printf (format, buffer + i);
  346.     }
  347.     else
  348.         printf (format, buffer);
  349. }
  350.  
  351. /* ruleset --- name a ruleset */
  352.  
  353. ruleset ()
  354. {
  355.     static int first = 1;
  356.     register char *cp = buffer + 1;
  357.  
  358.     if (first)
  359.     {
  360.         first = 0;
  361.         printf ("\n/* These are sample field definitons (cfc) */\n");
  362.         printf ("\nfield\n\tzero_or_more : match (0*);\n");
  363.         printf ("\tone_or_more : match (1*);\n");
  364.         printf ("\texactly_one : match (1);\n");
  365.         printf ("\tany_in_? : match (1) in ?;\n");
  366.         printf ("\tany_not_in_? : match (0) in ?;\n\n");
  367.     }
  368.  
  369.     printf ("ruleset\n\tRULESET_");
  370.     while (*cp && ! isspace (*cp))
  371.     {
  372.         putchar (*cp);
  373.         cp++;
  374.     }
  375.  
  376.     printf (" {");
  377.     if (*cp)
  378.         printf ("\t/* %s */", cp);
  379.     putchar ('\n');
  380.     inruleset++;
  381. }
  382.  
  383. /* rule --- print out a rule */
  384.  
  385. rule ()
  386. {
  387.     register char *cp = buffer + 1;
  388.     register char *cp2;
  389.     register int com = 0;
  390.  
  391.     /* first, split it up into LHS, RHS, COMMENT */
  392.  
  393.     while (*cp != '\t')
  394.         cp++;
  395.     *cp = '\0';
  396.  
  397.     cp++;
  398.     while (*cp == '\t')
  399.         cp++;
  400.     cp2 = cp;
  401.     while (*cp && *cp != '\t')
  402.         cp++;
  403.     if (*cp == '\t' && cp[1])
  404.     {
  405.         *cp = '\0';
  406.         com++;
  407.         cp++;
  408.         while (*cp == '\t')
  409.             cp++;
  410.     }
  411.  
  412.     /* now print */
  413.     lhs (buffer + 1);    /* left hand side */
  414.     if (com)
  415.         printf ("\t/* %s */", cp);
  416.     putchar ('\n');
  417.     rhs (cp2);        /* right hand side */
  418. }
  419.  
  420. /* lhs --- left hand side of a production */
  421.  
  422. lhs (text)
  423. char *text;
  424. {
  425.     register char *cp = text;
  426.     register int conditional = 0;
  427.     register int quoting = 0;
  428.  
  429.     printf ("\tif (");
  430.     for (; *cp; cp++)
  431.     {
  432.         switch (*cp) {
  433.         case '$':
  434.             if (quoting)
  435.             {
  436.                 quoting = 0;
  437.                 putchar ('"');
  438.             }
  439.             switch (*++cp) {
  440.             case '*':
  441.                 printf (" zero_or_more ");
  442.                 break;
  443.             case '+':
  444.                 printf (" one_or_more ");
  445.                 break;
  446.             case '-':
  447.                 printf (" exactly_one ");
  448.                 break;
  449.             case '=':
  450.                 printf (" any_in_%c ", *++cp);
  451.                 break;
  452.             case '~':
  453.                 printf (" any_not_in_%c ", *++cp);
  454.                 break;
  455.             case '?':
  456.                 printf (" ifset (%s, ", macro (*++cp));
  457.                 conditional++;
  458.                 break;
  459.             case '|':
  460.                 printf (", ");
  461.                 break;
  462.             case '.':
  463.                 putchar (')');
  464.                 conditional--;
  465.                 break;
  466.             case '1':
  467.             case '2':
  468.             case '3':
  469.             case '4':
  470.             case '5':
  471.             case '6':
  472.             case '7':
  473.             case '8':
  474.             case '9':
  475.                 printf ("$%c", *cp);
  476.                 break;
  477.             default:
  478.                 if (quoting)
  479.                     printf ("${%s}", macro (*cp));
  480.                 else
  481.                     printf ("$%s", macro (*cp));
  482.                 break;
  483.             }
  484.             break;
  485.         default:
  486.             if (ispunct (*cp))
  487.             {
  488.                 if (quoting)    /* end a literal */
  489.                 {
  490.                     quoting = 0;
  491.                     putchar ('"');
  492.                 }
  493.                 /* else
  494.                     do nothing */
  495.             }
  496.             else
  497.             {
  498.                 if (! quoting)    /* start a literal */
  499.                 {
  500.                     quoting = 1;
  501.                     putchar ('"');
  502.                 }
  503.                 /* else
  504.                     do nothing */
  505.             }
  506.             putchar (*cp);    /* print the character */
  507.             break;
  508.         }
  509.     }
  510.     if (quoting)
  511.         putchar ('"');
  512.     if (conditional)
  513.         die ("lhs");
  514.     printf (")");
  515. }
  516.  
  517. /* rhs --- right hand side of a production */
  518.  
  519. rhs (text)
  520. char *text;
  521. {
  522.     register char *cp = text;
  523.     char *index ();
  524.     register int open = 0;
  525.     register int conditional = 0;
  526.     register int quoting = 0;
  527.  
  528.     printf ("\t\t");
  529.  
  530.     if (*cp == '$' && index ("#@:", cp[1]) != NULL)
  531.         ;    /* not the default */
  532.     else
  533.     {
  534.         printf ("retry (");
  535.         open++;
  536.     }
  537.  
  538.     for (; *cp; cp++)
  539.     {
  540.         switch (*cp) {
  541.         case '$':
  542.             if (quoting)
  543.             {
  544.                 quoting = 0;
  545.                 putchar ('"');
  546.             }
  547.             switch (*++cp) {
  548.             case '>':
  549.                 printf ("RULESET_");
  550.                 for (cp++; *cp && isdigit (*cp); cp++)
  551.                     putchar (*cp);
  552.                 cp--;
  553.                 printf (" (");
  554.                 open++;
  555.                 break;
  556.             case '[':
  557.                 printf ("canon (");
  558.                 open++;
  559.                 break;
  560.             case ']':
  561.                 putchar (')');
  562.                 open--;
  563.                 break;
  564.             case '?':
  565.                 printf ("ifset (%s, ", macro (*++cp));
  566.                 conditional++;
  567.                 break;
  568.             case '|':
  569.                 putchar (',');
  570.                 break;
  571.             case '.':
  572.                 putchar (')');
  573.                 conditional--;
  574.                 break;
  575.             case '#':
  576.                 printf ("resolve (mailer (");
  577.                 if (strncmp (cp+1, "local$", 6) == 0
  578.                     || strncmp (cp+1, "error$", 6) == 0)
  579.                     goto skiphost;
  580.             loop1:
  581.                 for (cp++; *cp != '$'; cp++)
  582.                     putchar (*cp);
  583.                 *cp++;
  584.                 if (*cp != '@')
  585.                 {
  586.                     printf ("$%c", *cp);
  587.                     goto loop1;
  588.                 }
  589.                 printf ("),\n\t\t\t\thost (");
  590.             skiphost:
  591.             loop2:
  592.                 for (cp++; *cp != '$'; cp++)
  593.                     putchar (*cp);
  594.                 *cp++;
  595.                 if (*cp != ':')
  596.                 {
  597.                     printf ("$%c", *cp);
  598.                     goto loop2;
  599.                 }
  600.                 printf ("),\n\t\t\t\tuser (");
  601.                 for (cp++; *cp; cp++)
  602.                     putchar (*cp);
  603.                 printf ("))");
  604.                 goto out;    /* string is exhausted */
  605.                 break;
  606.             case '@':
  607.                 printf ("return (");
  608.                 open++;
  609.                 break;
  610.             case ':':
  611.                 printf ("next (");
  612.                 open++;
  613.                 break;
  614.             case '&':    /* RUTGERS addition */
  615.                 printf ("eval (%s)", macro (*++cp));
  616.                 break;
  617.             case '1':
  618.             case '2':
  619.             case '3':
  620.             case '4':
  621.             case '5':
  622.             case '6':
  623.             case '7':
  624.             case '8':
  625.             case '9':
  626.                 printf ("$%c", *cp);
  627.                 break;
  628.             default:
  629.                 if (quoting)
  630.                     printf ("${%s}", macro (*cp));
  631.                 else
  632.                     printf ("$%s", macro (*cp));
  633.                 break;
  634.             }
  635.             break;
  636.         default:
  637.             if (ispunct (*cp))
  638.             {
  639.                 if (quoting)    /* end a literal */
  640.                 {
  641.                     quoting = 0;
  642.                     putchar ('"');
  643.                 }
  644.                 /* else
  645.                     do nothing */
  646.             }
  647.             else
  648.             {
  649.                 if (! quoting)    /* start a literal */
  650.                 {
  651.                     quoting = 1;
  652.                     putchar ('"');
  653.                 }
  654.                 /* else
  655.                     do nothing */
  656.             }
  657.             putchar (*cp);    /* print the character */
  658.             break;
  659.         }
  660.     }
  661. out:
  662.     if (quoting)
  663.         putchar ('"');
  664.     while (open--)
  665.         putchar (')');
  666.     printf (";\n");
  667.     if (conditional)
  668.         die ("rhs");
  669. }
  670.  
  671. /* def --- define a macro */
  672.  
  673. def ()
  674. {
  675.     register char *mac = buffer + 1, *value = buffer + 2;
  676.     register int conditional = 0;
  677.  
  678.     printf ("macro\n\t%s = \"", macro (*mac));
  679.  
  680.     while (*value)
  681.     {
  682.         switch (*value) {
  683.         case '$':
  684.             switch (*++value) {
  685.             case '?':
  686.                 printf ("ifset (%s, ", macro (*++value));
  687.                 conditional++;
  688.                 break;
  689.             case '|':
  690.                 putchar (',');
  691.                 break;
  692.             case '.':
  693.                 putchar (')');
  694.                 conditional--;
  695.                 break;
  696.             default:
  697.                 printf ("${%s}", macro (*value));
  698.                 break;
  699.             }
  700.             break;
  701.         default:
  702.             putchar (*value);
  703.             break;
  704.         }
  705.         value++;
  706.     }
  707.     printf ("\";\n");
  708.     if (conditional)
  709.         die ("def");
  710. }
  711.  
  712. /* class --- define a class list */
  713.  
  714. class ()
  715. {
  716.     register char *name = buffer + 1, *value = buffer + 2;
  717.  
  718.     printf ("class\n\t%c = { ", *name);
  719.  
  720.     while (*value && isspace (*value))
  721.         value++;
  722.  
  723.     while (*value)
  724.     {
  725.         if (isspace (*value))
  726.         {
  727.             printf (", ");
  728.             while (isspace (*value))
  729.                 value++;
  730.             value--;    /* cancel loop */
  731.         }
  732.         else
  733.             putchar (*value);
  734.         value++;
  735.     }
  736.     printf (" };\n");
  737. }
  738.  
  739. /* fileclass --- define a class that is to be read from a file */
  740.  
  741. fileclass ()
  742. {
  743.     register char *name = buffer + 1, *value = buffer + 2;
  744.  
  745.     printf ("class\n\t%c = readclass (\"", *name);
  746.     for (; *value && !isspace (*value); value++)
  747.         putchar (*value);
  748.     putchar ('"');
  749.     while (*value && isspace (*value))
  750.         value++;
  751.     if (*value)
  752.         printf (", \"%s\"", value);
  753.     printf (");\n");
  754. }
  755.  
  756. /* mailer --- convert a mailer specification */
  757.  
  758. mailer ()
  759. {
  760.     register char *cp = buffer + 1;
  761.  
  762.     printf ("mailer\n\t");
  763.     for (; *cp != ','; cp++)
  764.         putchar (*cp);
  765.     cp++;
  766.     printf (" {\n");    /* just did mailer name */
  767.  
  768. #define skipname()    cp++; while (*cp != '=') cp++; cp++
  769. #define value()        for (; *cp && *cp != ','; cp++) putchar (*cp); cp++
  770.  
  771. loop:
  772.     while (*cp && isspace (*cp))
  773.         cp++;
  774.  
  775.     printf ("\t\t");
  776.     switch (*cp) {
  777.     case 'A':
  778.         skipname ();
  779.         printf ("Argv = \"");
  780.         for (; *cp && *cp != ','; cp++)
  781.         {
  782.             if (*cp == '$')    /* XXX: assume no conditionals */
  783.                 printf ("${%s}", macro (*++cp));
  784.             else
  785.                 putchar (*cp);
  786.         }
  787.         cp++;    /* do manually what value does */
  788.         putchar ('"');
  789.         break;
  790.  
  791.     case 'E':
  792.         skipname ();
  793.         printf ("Eol = \"");
  794.         value ();
  795.         putchar ('"');
  796.         break;
  797.  
  798.     case 'F':
  799.         skipname ();
  800.         printf ("Flags = { ");
  801.         for (; *cp && *cp != ','; cp++)
  802.         {
  803.             printf ("%s", mflags (*cp));
  804.             if (cp[1] && cp[1] != ',')
  805.                 printf (", ");
  806.         }
  807.         cp++;    /* do manually what value does */
  808.         printf (" }");
  809.         break;
  810.  
  811.     case 'M':
  812.         skipname ();
  813.         printf ("Maxsize = \"");
  814.         value ();
  815.         putchar ('"');
  816.         break;
  817.  
  818.     case 'P':
  819.         skipname ();
  820.         printf ("Path = \"");
  821.         value ();
  822.         putchar ('"');
  823.         break;
  824.  
  825.     case 'R':
  826.         skipname ();
  827.         printf ("Recipient = RULESET_");
  828.         value ();
  829.         break;
  830.  
  831.     case 'S':
  832.         skipname ();
  833.         printf ("Sender = RULESET_");
  834.         value ();
  835.         break;
  836.  
  837.     case '\0':
  838.         goto done;
  839.     }
  840.  
  841.     if (cp[-1] && cp[-1] == ',')
  842.     {
  843.         printf (",\n");
  844.         goto loop;
  845.     }
  846.     else
  847.         putchar ('\n');
  848.  
  849. done:
  850.     /* handle continuation lines */
  851.     if (ngets (buffer) != NULL)
  852.     {
  853.         line++;
  854.         if (buffer[0] == '\t')
  855.         {
  856.             cp = buffer;
  857.             goto loop;
  858.         }
  859.         else
  860.             ungets (buffer);
  861.     }
  862.     else
  863.         ungets (NULL);
  864.     
  865.     printf ("\t};\n");
  866.  
  867. #undef value
  868. #undef skipname
  869. }
  870.  
  871. /* header --- define sendmail headers */
  872.  
  873. header ()
  874. {
  875.     register char *cp = buffer + 1;
  876.     register int flags = 0;
  877.     register int conditional = 0;
  878.  
  879.     printf ("header\n\t");
  880.     if (*cp == '?')        /* header for mailers  with these flags */
  881.     {
  882.         flags++;
  883.         printf ("for (");
  884.         for (cp++; *cp != '?'; cp++)
  885.         {
  886.             printf ("%s", mflags (*cp));
  887.             if (cp[1] != '?')
  888.                 putchar (',');
  889.         }
  890.         printf (") {\n\t\t");
  891.         cp++;    /* skip final '?' */
  892.     }
  893.  
  894.     printf ("define (\"");
  895.     for (; *cp && ! isspace (*cp); cp++)
  896.         putchar (*cp);
  897.     printf ("\", \"");
  898.  
  899. body:
  900.     while (*cp)
  901.     {
  902.         switch (*cp) {
  903.         case '$':
  904.             switch (*++cp) {
  905.             case '?':
  906.                 printf ("ifset (%s, ", macro (*++cp));
  907.                 conditional++;
  908.                 break;
  909.             case '|':
  910.                 putchar (',');
  911.                 break;
  912.             case '.':
  913.                 putchar (')');
  914.                 conditional--;
  915.                 break;
  916.             default:
  917.                 printf ("${%s}", macro (*cp));
  918.                 break;
  919.             }
  920.             break;
  921.         default:
  922.             putchar (*cp);
  923.             break;
  924.         }
  925.         cp++;
  926.     }
  927.  
  928.     /* handle continuation lines */
  929.     if (ngets (buffer) != NULL)
  930.     {
  931.         line++;
  932.         if (buffer[0] == '\t')
  933.         {
  934.             printf ("\\\n");
  935.             cp = buffer + 1;
  936.             goto body;
  937.         }
  938.         else
  939.             ungets (buffer);
  940.     }
  941.     else
  942.         ungets (NULL);
  943.  
  944.     printf ("\");\n");
  945.  
  946.     if (flags)
  947.         printf ("\t};\n");
  948. }
  949.  
  950. /* option --- translate a sendmail option to an ease option */
  951.  
  952. option ()
  953. {
  954.     register char *name = buffer + 1, *value = buffer + 2;
  955.  
  956.     printf ("options\n\t");
  957.     if (*name == 'd')        /* delivery */
  958.         printf ("o_delivery = %s;\n", delivoption (*value));
  959.     else if (*name == 'e')        /* handling */
  960.         printf ("o_handling = %s;\n", handle_option (*value));
  961.     else
  962.         printf ("%s = \"%s\";\n", optionname (*name), value);
  963. }
  964.  
  965. /* trusted --- define the list of trusted users */
  966.  
  967. trusted ()
  968. {
  969.     register char *cp = buffer + 1;
  970.  
  971.     while (*cp)
  972.     {
  973.         if (isspace (*cp))
  974.             *cp = ',';
  975.         cp++;
  976.     }
  977.     printf ("trusted\n\t{ %s };\n", buffer+1);
  978. }
  979.  
  980. /* precedence --- define the precedence of a message class */
  981.  
  982. precedence ()
  983. {
  984.     register char *cp = buffer + 1;
  985.  
  986.     printf ("precedence\n\t");
  987.     for (; *cp && *cp != '='; cp++)
  988.         putchar (*cp);
  989.     printf (" = %s;\n", ++cp);
  990. }
  991.  
  992. /* other --- not a sendmail control line */
  993.  
  994. other ()
  995. {
  996.     printf ("%s\n", buffer);
  997. }
  998.  
  999. die (routine)
  1000. char *routine;
  1001. {
  1002.     fprintf (stderr, "%s: malformed input line %d: fatal error\n",
  1003.             routine, line);
  1004.     exit (1);
  1005. }
  1006.  
  1007. /* macro --- return name for sendmail predefined macro */
  1008.  
  1009. char *macro (c)
  1010. char c;
  1011. {
  1012.     static char buf[2] = { '\0', '\0' };
  1013.  
  1014.     switch (c) {
  1015.     case 'a':    /* The origination date in Arpanet format */
  1016.         return ("m_odate");
  1017.  
  1018.     case 'b':    /* The current date in Arpanet format */
  1019.         return ("m_adate");
  1020.  
  1021.     case 'c':    /* The hop count */
  1022.         return ("m_hops");
  1023.  
  1024.     case 'd':    /* The date in UNIX (ctime) format */
  1025.         return ("m_udate");
  1026.  
  1027.     case 'e':    /* The SMTP entry message */
  1028.         return ("m_smtp");
  1029.  
  1030.     case 'f':    /* The sender (from) address */
  1031.         return ("m_saddr");
  1032.  
  1033.     case 'g':    /* The sender address relative to the recipient */
  1034.         return ("m_sreladdr");
  1035.  
  1036.     case 'h':    /* The recipient host */
  1037.         return ("m_rhost");
  1038.  
  1039.     case 'i':    /* The queue id */
  1040.         return ("m_qid");
  1041.  
  1042.     case 'j':    /* The official domain name for this site */
  1043.         return ("m_oname");
  1044.  
  1045.     case 'l':    /* The format of the UNIX from line */
  1046.         return ("m_ufrom");
  1047.  
  1048.     case 'n':    /* The name of the daemon (for error messages) */
  1049.         return ("m_daemon");
  1050.  
  1051.     case 'o':    /* The set of "operators" in addresses */
  1052.         return ("m_addrops");
  1053.  
  1054.     case 'p':    /* Sendmail's pid */
  1055.         return ("m_pid");
  1056.  
  1057.     case 'q':    /* The default format of sender address */
  1058.         return ("m_defaddr");
  1059.  
  1060.     case 'r':    /* Protocol used */
  1061.         return ("m_protocol");
  1062.  
  1063.     case 's':    /* Sender's host name */
  1064.         return ("m_shostname");
  1065.  
  1066.     case 't':    /* A numeric representation of the current time */
  1067.         return ("m_ctime");
  1068.  
  1069.     case 'u':    /* The recipient user */
  1070.         return ("m_ruser");
  1071.  
  1072.     case 'v':    /* The version number of sendmail */
  1073.         return ("m_version");
  1074.  
  1075.     case 'w':    /* The hostname of this site */
  1076.         return ("m_sitename");
  1077.  
  1078.     case 'x':    /* The full name of the sender */
  1079.         return ("m_sname");
  1080.  
  1081.     case 'y':    /* The id of the sender's tty */
  1082.         return ("m_stty");
  1083.  
  1084.     case 'z':    /* The home directory of the recipient */
  1085.         return ("m_rhdir");
  1086.  
  1087.     default:
  1088.         buf[0] = c;
  1089.         return (buf);
  1090.     }
  1091. }
  1092.  
  1093. #define docompat(val)    if (compat) goto warn; else return (val)
  1094.  
  1095. /* mflags --- convert sendmail mailer flags to ease names */
  1096.  
  1097. char *mflags (c)
  1098. char c;
  1099. {
  1100.     static char buf[2] = { '\0', '\0' };
  1101.  
  1102.     switch (c) {
  1103.     case 'f':    return ("f_ffrom");
  1104.     case 'r':    return ("f_rfrom");
  1105.     case 'S':    return ("f_noreset");
  1106.     case 'n':    return ("f_noufrom");
  1107.     case 'l':    return ("f_locm");
  1108.     case 's':    return ("f_strip"); 
  1109.     case 'm':    return ("f_mult");
  1110.     case 'F':    return ("f_from");
  1111.     case 'D':    return ("f_date");
  1112.     case 'M':    return ("f_mesg");
  1113.     case 'x':    return ("f_full");    
  1114.     case 'P':    return ("f_return");    
  1115.     case 'u':    return ("f_upperu");    
  1116.     case 'h':    return ("f_upperh");    
  1117.     case 'A':    return ("f_arpa");    
  1118.     case 'U':    return ("f_ufrom");    
  1119.     case 'e':    return ("f_expensive");    
  1120.     case 'X':    return ("f_dot");    
  1121.     case 'L':    return ("f_llimit");    
  1122.     case 'p':    return ("f_retsmtp");    
  1123.     case 'I':    return ("f_smtp");    
  1124.     case 'C':    return ("f_addrw");    
  1125.     case 'E':    docompat ("f_escape");
  1126.     default:
  1127.     warn:
  1128.         fprintf (stderr,
  1129.             "warning: non standard mailer flag '%c' on line %d\n",
  1130.                 c, line);
  1131.         buf[0] = c;
  1132.         return buf;
  1133.     }
  1134. }
  1135.  
  1136. /* optionname --- convert sendmail options to ease names */
  1137.  
  1138. char *optionname (c)
  1139. char c;
  1140. {
  1141.     static char buf[2] = { '\0', '\0' };
  1142.  
  1143.     switch (c) {
  1144.     case 'A':    return ("o_alias");
  1145.     case 'a':    return ("o_ewait");
  1146.     case 'B':    return ("o_bsub");
  1147.     case 'c':    return ("o_qwait");
  1148.     case 'd':    return ("o_delivery");
  1149.     case 'D':    return ("o_rebuild");
  1150.     case 'e':    return ("o_handling");
  1151.     case 'F':    return ("o_tmode");
  1152.     case 'f':    return ("o_usave");
  1153.     case 'g':    return ("o_gid");
  1154.     case 'H':    return ("o_fsmtp");
  1155.     case 'i':    return ("o_skipd");
  1156.     case 'L':    return ("o_slog");
  1157.     case 'm':    return ("o_rsend");
  1158.     case 'N':    return ("o_dnet");
  1159.     case 'o':    return ("o_hformat");
  1160.     case 'Q':    return ("o_qdir");
  1161.     case 'q':    docompat ("o_qfactor");
  1162.     case 'r':    return ("o_tread");
  1163.     case 'S':    return ("o_flog");
  1164.     case 's':    return ("o_safe");
  1165.     case 'T':    return ("o_qtimeout");
  1166.     case 't':    return ("o_timezone");
  1167.     case 'u':    return ("o_dmuid");
  1168.     case 'v':    return ("o_verbose");
  1169.     case 'W':    return ("o_wizpass");
  1170.     case 'x':    return ("o_loadq");
  1171.     case 'X':    return ("o_loadnc");
  1172.     case 'Y':    docompat ("o_newproc");
  1173.     case 'Z':    docompat ("o_prifactor");
  1174.     case 'z':    docompat ("o_waitfactor");
  1175.     default:
  1176.     warn:
  1177.         fprintf (stderr,
  1178.             "warning: non standard option '%c' on line %d\n",
  1179.                 c, line);
  1180.         buf[0] = c;
  1181.         return buf;
  1182.     }
  1183. }
  1184.  
  1185. /* delivoption --- convert sendmail delivery option value to ease name */
  1186.  
  1187. char *delivoption (c)
  1188. char c;
  1189. {
  1190.     static char buf[2] = { '\0', '\0' };
  1191.  
  1192.     switch (c) {
  1193.     case 'i':    return ("d_interactive");
  1194.     case 'b':    return ("d_background");
  1195.     case 'q':    return ("d_queue");
  1196.     default:
  1197.         fprintf (stderr,
  1198.     "warning: non standard delivery option '%c' on line %d\n", c, line);
  1199.         buf[0] = c;
  1200.         return buf;
  1201.     }
  1202. }
  1203.  
  1204. /* handle_option --- convert sendmail handling option value to ease name */
  1205.  
  1206. char *handle_option (c)
  1207. char c;
  1208. {
  1209.     static char buf[2] = { '\0', '\0' };
  1210.  
  1211.     switch (c) {
  1212.     case 'p':    return ("h_print");
  1213.     case 'q':    return ("h_exit");
  1214.     case 'm':    return ("h_mail");
  1215.     case 'w':    return ("h_write");
  1216.     case 'e':    return ("h_mailz");
  1217.     default:
  1218.         fprintf (stderr,
  1219.     "warning: non standard handling option '%c' on line %d\n", c, line);
  1220.         buf[0] = c;
  1221.         return buf;
  1222.     }
  1223. }
  1224.  
  1225. /*
  1226.  * "buffered" i/o routines. These are necessary since
  1227.  * mail headers may have continuation lines, and we can't see if
  1228.  * a continuation line is there without getting it. If it isn't,
  1229.  * just put it back.
  1230.  */
  1231.  
  1232. int saved = 0;
  1233. char *saveb = NULL;
  1234.  
  1235. /* ngets --- get a line of input from either saved buffer or stdin */
  1236.  
  1237. char *ngets (bp)
  1238. char *bp;
  1239. {
  1240.     if (! saved)
  1241.         return (gets (bp));
  1242.  
  1243.     saved = 0;
  1244.     bp = saveb;
  1245.     saveb = NULL;
  1246.     return (bp);
  1247. }
  1248.  
  1249. /* ungets --- put a buffer back on the input, so to speak */
  1250.  
  1251. void ungets (bp)
  1252. char *bp;
  1253. {
  1254.     saved = 1;
  1255.     saveb = bp;
  1256.     line--;
  1257. }
  1258. SHAR_EOF
  1259. fi # end of overwriting check
  1260. #    End of shell archive
  1261. exit 0
  1262.  
  1263.